/***************************************************************************
 * Copyright 2012-2013 TXT e-solutions SpA
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * This work was performed within the IoT_at_Work Project
 * and partially funded by the European Commission's
 * 7th Framework Programme under the contract ICT-257367.
 *
 * Authors:
 *      Salvatore Piccione (TXT e-solutions SpA)
 *
 * Contributors:
 *        Domenico Rotondi (TXT e-solutions SpA)
 **************************************************************************/
package it.txt.ens.client.gui.standalone;

import it.txt.ens.client.application.exception.ApplicationFailureException;
import it.txt.ens.client.core.ENSClient;
import it.txt.ens.client.core.ENSEvent;
import it.txt.ens.client.core.factory.ENSClientFactory;
import it.txt.ens.client.gui.standalone.util.ApplicationPropertiesRepository;
import it.txt.ens.client.gui.standalone.util.JTextAreaStream;
import it.txt.ens.client.gui.standalone.util.RequestFactory;
import it.txt.ens.client.publisher.ENSPublisher;
import it.txt.ens.client.publisher.ENSPublishingException;
import it.txt.ens.client.publisher.impl.BasicENSEventFactory;
import it.txt.ens.client.subscriber.ENSEventListener;
import it.txt.ens.client.subscriber.ENSSubscriber;
import it.txt.ens.client.subscriber.ENSSubscriptionException;
import it.txt.ens.core.factory.ENSAuthzServiceConnectionParametersFactory;
import it.txt.ens.core.factory.ENSResourceFactory;
import it.txt.ens.core.factory.X509CertificateRetrievalParametersFactory;
import it.txt.ens.schema.factory.model.FailureResponseDetails;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.SystemColor;
import java.awt.Toolkit;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;

import com.rabbitmq.client.AlreadyClosedException;

/**
 * Class that extend a JFrame. This class can represent a panel of control for
 * Client Rpc
 * 
 * @author Carbone Matteo
 * @author Salvatore Piccione (TXT e-solutions SpA - salvatore.piccione AT txtgroup.com)
 */
public class ENSClientGUI extends JFrame {

	private static final long serialVersionUID = 3247040311440898024L;
	private static final String PUBLISH_BOTTLES_NUMBER = "publish - Bottles number";
    private static final String PUBLISH_BOTTLES_WEIGHT = "publish - Bottles weight";
    private static final String PUBLISH_EMD_EVENTS = "publish - EMD events";
    private static final String PUBLISH_FILLING_LEVELS = "publish - Filling levels";
    private static final String PUBLISH_ALERTS = "publish - Alerts";
    private static final String SUBSCRIBE = "subscribe";
	private static final String LOCALHOST = "localhost";
	private static final String DEFAULT_PORT = "5672";
	
    private JDesktopPane jDesktopPane = null;
	private JLabel jLabelUser = null;
	private JTextField jTextFieldUser = null;
	private JLabel jLabelRoutingKey = null;
	private JTextField jTextFieldRoutingKey = null;
	private JLabel jLabelOperation = null;
	private JLabel jLabelTitle = null;
	private JTextArea jTextAreaReply = null;
	private JButton jButtonReadMsg = null;
	private JButton jButtonClearRequest = null;
	private JScrollPane jScrollPane = null;
	private JButton jButtonSendRequestRPC = null;
	private JButton jButtonExit = null;
	private JComboBox jComboBoxOperation = null;
	private JButton jButtonStopOperation = null;
	private JButton jButtonSendMsg = null;
	private JTextField jTextFieldIPHost = null;
	private JTextField jTextFieldPort = null;
	private JLabel jLabelHost = null;
	private JLabel jLabelPort = null;
//	private JProgressBar jProgressBar = null;
	private JTextField namespace_textField;
	private Color backgroundColor = null;
	
	private ENSClient app;
    private String routingKey;
    private Thread publishingThread;
    private PublishingRunnable publishingRunnable;
    private String requestedOperation;

	
	/**
	 * Constructor
	 */
	public ENSClientGUI() {
		this.inizialize();
	}

	private void inizialize() {
		this.setSize(new Dimension(400, 475));
		getContentPane().add(getJDesktopPane(), null);
		this.setBackground(Color.DARK_GRAY);
		this.setResizable(false);
		this.setLocation(100, 100);

		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		int locationX = (int) (screenSize.width) / 6;
		int locationY = (int) (screenSize.height) / 5;
		this.setLocation(new Point(locationX + 178, locationY));

		this.setTitle("ENS Client");
	}

	/**
	 * This method initializes jDesktopPane
	 * 
	 * @return javax.swing.JDesktopPane
	 */
	private JDesktopPane getJDesktopPane() {
		if (jDesktopPane == null) {
			jLabelPort = new JLabel();
			jLabelPort.setBounds(new Rectangle(5, 99, 80, 18));
			jLabelPort.setText("Port");
			jLabelPort.setFont(new Font("Dialog", Font.PLAIN, 11));
			
			jLabelHost = new JLabel();
			jLabelHost.setBounds(new Rectangle(5, 84, 80, 18));
			jLabelHost.setText("IP Host");
			jLabelHost.setFont(new Font("Dialog", Font.PLAIN, 11));
			
			jLabelTitle = new JLabel();
			jLabelTitle.setFont(new Font("Dialog", Font.BOLD, 11));
			jLabelTitle.setBounds(new Rectangle(5, 0, 130, 15));
			jLabelTitle.setText("Request parameters");

			jLabelUser = new JLabel();
			jLabelUser.setBounds(new Rectangle(5, 20, 80, 18));
			jLabelUser.setText("UserID");
			jLabelUser.setFont(new Font("Dialog", Font.PLAIN, 11));
			
			jLabelRoutingKey = new JLabel();
			jLabelRoutingKey.setBounds(new Rectangle(190, 20, 80, 18));
			jLabelRoutingKey.setText("Pattern");
			jLabelRoutingKey.setFont(new Font("Dialog", Font.PLAIN, 11));
			
			jLabelOperation = new JLabel();
			jLabelOperation.setBounds(new Rectangle(190, 38, 60, 18));
			jLabelOperation.setText("Operation");
			jLabelOperation.setFont(new Font("Dialog", Font.PLAIN, 11));

			jDesktopPane = new JDesktopPane();
            jDesktopPane.setBounds(new Rectangle(5, 50, 375, 400));
			jDesktopPane.setBackground(SystemColor.window);
        
            jDesktopPane.add(getJButtonReadMsg(), null);
            jDesktopPane.add(getJButtonClearRequest(), null);
            jDesktopPane.add(getJButtonExit(), null);
            jDesktopPane.add(jLabelUser, null);
			jDesktopPane.add(getJTextFieldUser(), null);
			jDesktopPane.add(jLabelRoutingKey, null);
			jDesktopPane.add(getJTextFieldQueue(), null);

            jDesktopPane.add(getNamespace_textField());
            
			jDesktopPane.add(jLabelOperation, null);
			jDesktopPane.add(jLabelTitle, null);

			jDesktopPane.add(getJScrollPane(), null);
			jDesktopPane.add(getJButtonSendRequestRPC(), null);
			jDesktopPane.add(getJComboBoxOperation(), null);
			jDesktopPane.add(getJButtonStopOperation(), null);
			jDesktopPane.add(getJButtonSendMsg(), null);

			jDesktopPane.add(getJTextFieldIPHost(), null);
			jDesktopPane.add(getJTextFieldPort(), null);
			jDesktopPane.add(jLabelHost, null);
			jDesktopPane.add(jLabelPort, null);
//			jDesktopPane.add(getJProgressBar(), null);
			
			jTextFieldIPHost.setText(LOCALHOST);
			jTextFieldPort.setText(DEFAULT_PORT);
						
			JLabel namespace_label = new JLabel();
			namespace_label.setText("Namespace");
			namespace_label.setFont(new Font("Dialog", Font.PLAIN, 11));
			namespace_label.setBounds(new Rectangle(5, 60, 80, 18));
			namespace_label.setBounds(5, 38, 80, 18);
			jDesktopPane.add(namespace_label);

		}
		return jDesktopPane;
	}
	
	private JTextField getNamespace_textField() {
	    namespace_textField = new JTextField();
        namespace_textField.setBounds(85, 39, 95, 18);
        namespace_textField.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent e) {
                unmarkFieldAsMissing(namespace_textField);
            }
        });
        return namespace_textField;
	}

	/**
	 * This method initializes jTextFieldUser
	 * 
	 * @return javax.swing.JTextField
	 */
	private JTextField getJTextFieldUser() {
		if (jTextFieldUser == null) {
			jTextFieldUser = new JTextField();
			jTextFieldUser.setBounds(new Rectangle(85, 20, 95, 18));
			jTextFieldUser.addFocusListener(new java.awt.event.FocusAdapter() {
				public void focusGained(java.awt.event.FocusEvent e) {
					unmarkFieldAsMissing(jTextFieldUser);
					
				}
			});			
		}
		return jTextFieldUser;
	}

	/**
	 * This method initializes jTextFieldQueue
	 * 
	 * @return javax.swing.JTextField
	 */
	private JTextField getJTextFieldQueue() {
		if (jTextFieldRoutingKey == null) {
			jTextFieldRoutingKey = new JTextField();
			jTextFieldRoutingKey.setBounds(new Rectangle(295, 20, 95, 18));
			jTextFieldRoutingKey.addFocusListener(new java.awt.event.FocusAdapter() {
				public void focusGained(java.awt.event.FocusEvent e) {
				    unmarkFieldAsMissing(jTextFieldRoutingKey);
				}
			});
		}
		return jTextFieldRoutingKey;
	}

	/**
	 * This method initializes jTextFieldReply on this textArea are redirect all
	 * output stream of standard out
	 * 
	 * @return javax.swing.JTextField
	 */
	private JTextArea getJTextAreaReply() {
		if (jTextAreaReply == null) {
			jTextAreaReply = new JTextArea();
			jTextAreaReply.setBounds(5, 198, 403, 139);
			jTextAreaReply.setEditable(false);
			jTextAreaReply.setBackground(Color.DARK_GRAY);
			jTextAreaReply.setForeground(Color.cyan);
			try {
				new JTextAreaStream().redirectSystemOutputTo(jTextAreaReply);
			} catch (IOException ex) {
				System.out.println("ERROR: on redirect standard output!!!");
			}
		}
		return jTextAreaReply;
	}

	/**
	 * This method initializes jScrollPane contenent jTextArea which display
	 * standard out contains a JTextArea that shows the standard out
	 * 
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getJScrollPane() {
		if (jScrollPane == null) {
			jScrollPane = new JScrollPane();
			jScrollPane.setBounds(new Rectangle(5, 141, 385, 221));
			jScrollPane.setViewportView(getJTextAreaReply());
			jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		}
		return jScrollPane;
	}

	/**
	 * This method initializes jButtonSendOperation This JButton starts the
	 * service listening on work queue if the answer of ServerRpc is positive
	 * 
	 * @return javax.swing.JButton
	 */
	public JButton getJButtonReadMsg() {
	    final String START_READ_MODE_LABEL = "Start reading";	    
		if (jButtonReadMsg == null) {
			jButtonReadMsg = new JButton();
			jButtonReadMsg.setBounds(new Rectangle(138, 373, 125, 18));
			jButtonReadMsg.setText(START_READ_MODE_LABEL);
			jButtonReadMsg.setFont(new Font("Dialog", Font.BOLD, 11));
			jButtonReadMsg.setForeground(Color.red);
			jButtonReadMsg.setEnabled(false);
			jButtonReadMsg.addMouseListener(new java.awt.event.MouseAdapter() {
				public void mouseClicked(java.awt.event.MouseEvent e) {
				    try {
			            //start subscription
			            if (app instanceof ENSSubscriber) {
			                ENSSubscriber sub = (ENSSubscriber) app;
			                sub.registerEventListener(new SubscriberListener());
                            jButtonReadMsg.setEnabled(false);
                            jButtonSendRequestRPC.setEnabled(false); 
                            jButtonStopOperation.setEnabled(true);
			                sub.subscribe();
			            } else {
			                throw new RuntimeException("The client application is not a subscriber!");
			            }
                    } catch (IllegalStateException e1) {
                        System.err.print("An error occurred when starting reading messages");
                        e1.printStackTrace(System.err);
                    } catch (ENSSubscriptionException e1) {
                        System.err.print("An error occurred when starting reading messages");
                        e1.printStackTrace(System.err);
                    }
			    }
			});
		}
		return jButtonReadMsg;
	}

	/**
	 * /** This method initializes jButtonCreateRequest This JButton enable the
	 * user of insert request, refreshing all fields
	 * 
	 * @return javax.swing.JButton
	 */
	private JButton getJButtonClearRequest() {
		if (jButtonClearRequest == null) {
			jButtonClearRequest = new JButton();
			jButtonClearRequest.setBounds(new Rectangle(270, 64, 120, 20));
			jButtonClearRequest.setText("Clear");
			jButtonClearRequest.setFont(new Font("Dialog", Font.BOLD, 11));
			jButtonClearRequest
					.addMouseListener(new java.awt.event.MouseAdapter() {
						public void mouseClicked(java.awt.event.MouseEvent e) {
							jTextFieldUser.requestFocus();
							clearField(jTextFieldRoutingKey);
							clearField(namespace_textField);
							clearField(jTextFieldUser);
							clearField(jTextFieldIPHost);
							jTextFieldIPHost.setText(LOCALHOST);
							clearField(jTextFieldPort);
							jTextFieldPort.setText(DEFAULT_PORT);
							clearComboBox(jComboBoxOperation);
						}
					});

		}
		return jButtonClearRequest;
	}

	/**
	 * This method initializes jButtonsenrRequestRPC Send request on
	 * request_queue, with RPC service, and waiting the answers on the exclusive
	 * reservated queue for this
	 * 
	 * @return javax.swing.JButton
	 */
	private JButton getJButtonSendRequestRPC() {
		if (jButtonSendRequestRPC == null) {
			jButtonSendRequestRPC = new JButton();
			jButtonSendRequestRPC.setBounds(new Rectangle(270, 99, 120, 20));
			jButtonSendRequestRPC.setText("Send Request");
			jButtonSendRequestRPC.setFont(new Font("Dialog", Font.BOLD, 11));
			jButtonSendRequestRPC.setForeground(Color.BLUE);
			jButtonSendRequestRPC
					.addMouseListener(new java.awt.event.MouseAdapter() {
                        public void mouseClicked(java.awt.event.MouseEvent e) {
					        String userID = jTextFieldUser.getText();
							String namespace = namespace_textField.getText();
							routingKey = jTextFieldRoutingKey.getText();
							requestedOperation = jComboBoxOperation.getSelectedItem().toString();
							String rabbitMQHost = jTextFieldIPHost.getText();
							String rabbitMQPort = jTextFieldPort.getText();
                            
							if (userID.isEmpty() || namespace.isEmpty() || routingKey.isEmpty() || 
							        requestedOperation.isEmpty() || rabbitMQHost.isEmpty()  || rabbitMQPort.isEmpty()) {
							    if (userID.isEmpty())
							        markFieldAsMissing(jTextFieldUser);
							    if (namespace.isEmpty())
							        markFieldAsMissing(namespace_textField);
							    if (routingKey.isEmpty())
							        markFieldAsMissing(jTextFieldRoutingKey);
							    if (requestedOperation.isEmpty())
							        markComboBoxAsMissing(jComboBoxOperation);
							    if (rabbitMQHost.isEmpty())
							        markFieldAsMissing(jTextFieldIPHost);
							    if (rabbitMQPort.isEmpty())
                                    markFieldAsMissing(jTextFieldPort);
							} else {
								jTextAreaReply.setText("");
                                
								HashMap<String, String> settings = new HashMap<String, String>();
								Enumeration<Object> keys = ApplicationPropertiesRepository.APPLICATION_PROPERTIES.keys();
								String key;
								while (keys.hasMoreElements()) {
								    key = (String) keys.nextElement();
								    settings.put(key, ApplicationPropertiesRepository.APPLICATION_PROPERTIES.getProperty(key));
								}
								
								settings.put(ENSResourceFactory.NAMESPACE, namespace);
								settings.put(ENSResourceFactory.PATTERN, routingKey);
								settings.put(ENSClientFactory.SUBJECT_ID_KEY, userID);
								settings.put(X509CertificateRetrievalParametersFactory.SUBJECT_ID, userID);
								settings.put(ENSAuthzServiceConnectionParametersFactory.BROKER_HOST, rabbitMQHost);
								settings.put(ENSAuthzServiceConnectionParametersFactory.BROKER_PORT, rabbitMQPort);
								
								try {
                                    ENSClientGUI.this.app = RequestFactory.startGuestApplication(
                                            requestedOperation, settings );
    								//the application has been started
                                    if (ENSClientGUI.this.app != null) {
    									if (requestedOperation.equals(SUBSCRIBE)) {
    									    System.out.println("The client has been authorized to subscribe to the namespace '" + 
    									            namespace + "'. Target pattern:: " + routingKey);
    										jButtonReadMsg.setEnabled(true);
                                            jButtonSendMsg.setEnabled(false);
    									}else {
    									    System.out.println("The client has been authorized to publish on the namespace '" + 
                                                namespace + "'. Target pattern:: " + routingKey);
    										jButtonSendMsg.setEnabled(true);
                                            jButtonReadMsg.setEnabled(false);
    									}
    									jButtonSendRequestRPC.setEnabled(false);
    								} else {
    								    //THIS SHOULD NEVER HAPPEN!!!
    									jButtonReadMsg.setEnabled(false);
                                        jButtonSendMsg.setEnabled(false);
    								}
    							}
    					        catch (ApplicationFailureException appFailure) {
    					            System.out.println("**********CLIENT FAILURE**********");
    					            JOptionPane.showMessageDialog(null,
    					                    appFailure.getMessage(), "Client failure",
                                            JOptionPane.ERROR_MESSAGE);
    					            FailureResponseDetails failureDetails;
    					            if ((failureDetails = appFailure.getFailureDetails()) != null) {
    					                System.out.println("Code:: " + failureDetails.getErrorCode());
    					                System.out.println("Reason:: " + failureDetails.getErrorReason());
    					            } else {
    					                StringWriter stringWriter = new StringWriter();
    					                PrintWriter printWriter = new PrintWriter(stringWriter, true);
    					                appFailure.printStackTrace(printWriter);
    					                printWriter.close();
    					                System.out.println(stringWriter.getBuffer().toString());
    					            }
    					            System.out.println("**********************************");
                                } catch (Throwable t) {
                                    System.out.println("**********APPLICATION FAILURE**********");
                                    JOptionPane.showMessageDialog(null,
                                            t.getMessage(), "Application failure",
                                            JOptionPane.ERROR_MESSAGE);
                                    StringWriter stringWriter = new StringWriter();
                                    PrintWriter printWriter = new PrintWriter(stringWriter, true);
                                    t.printStackTrace(printWriter);
                                    printWriter.close();
                                    System.out.println(stringWriter.getBuffer().toString());
                                    System.out.println("***************************************");
                                }
							}
						}
			});

		}
		return jButtonSendRequestRPC;
	}

	/**
	 * This method initializes jButtonExit
	 * 
	 * @return javax.swing.JButton
	 */
	private JButton getJButtonExit() {
		if (jButtonExit == null) {
			jButtonExit = new JButton();
			jButtonExit.setText("Exit");
			jButtonExit.setFont(new Font("Dialog", Font.ITALIC, 12));
			jButtonExit.setBounds(new Rectangle(335, 410, 55, 15));
			jButtonExit.addMouseListener(new java.awt.event.MouseAdapter() {
				public void mouseClicked(java.awt.event.MouseEvent e) {
					System.exit(-1);
				}
			});

		}
		return jButtonExit;
	}

	/**
	 * This method initializes jComboBoxOperation contain the values of the
	 * operation for user (Config, Write, Read")
	 * 
	 * @return javax.swing.JComboBox
	 */
	private JComboBox getJComboBoxOperation() {
		if (jComboBoxOperation == null) {
			jComboBoxOperation = new JComboBox();
			backgroundColor = jComboBoxOperation.getBackground();
			jComboBoxOperation.setBounds(new Rectangle(250, 39, 140, 18));
			jComboBoxOperation.addItem("");
            jComboBoxOperation.addItem(PUBLISH_ALERTS);
            jComboBoxOperation.addItem(PUBLISH_BOTTLES_NUMBER);
            jComboBoxOperation.addItem(PUBLISH_BOTTLES_WEIGHT);
            jComboBoxOperation.addItem(PUBLISH_EMD_EVENTS);
            jComboBoxOperation.addItem(PUBLISH_FILLING_LEVELS);
			jComboBoxOperation.addItem(SUBSCRIBE);
			jComboBoxOperation.setFont(new Font("Dialog", Font.BOLD, 11));
			jComboBoxOperation.addFocusListener(new java.awt.event.FocusAdapter() {
                public void focusGained(java.awt.event.FocusEvent e) {
                    unmarkComboBoxAsMissing(jComboBoxOperation);
                }
            });
		}
		return jComboBoxOperation;
	}

	/**
	 * This method initializes jButtonStopOperation stopped the listener
	 * 
	 * @return javax.swing.JButton
	 */
	private JButton getJButtonStopOperation() {
		if (jButtonStopOperation == null) {
			jButtonStopOperation = new JButton();
			jButtonStopOperation.setBounds(new Rectangle(270, 373, 120, 18));
			jButtonStopOperation.setText("Stop operation");
			jButtonStopOperation.setFont(new Font("Dialog", Font.BOLD, 11));
			jButtonStopOperation.setForeground(Color.red);
			jButtonStopOperation.setEnabled(false);
			jButtonStopOperation
					.addMouseListener(new java.awt.event.MouseAdapter() {
						public void mouseClicked(java.awt.event.MouseEvent e) {
							try {
                                if (ENSClientGUI.this.app instanceof ENSSubscriber) {
                                    ENSSubscriber sub = (ENSSubscriber) ENSClientGUI.this.app;
                                    sub.unsubscribe();
                                    System.out.println("The event subscription has been stopped");
                                } else if (ENSClientGUI.this.app != null) {
                                    publishingRunnable.stop();
                                    publishingThread.join();
//                                    if (ENSClientGUI.this.app.isConnected())
//                                        ENSClientGUI.this.app.disconnect();
                                }
                                if (ENSClientGUI.this.app.isConnected())
                                    ENSClientGUI.this.app.disconnect();
                                jButtonReadMsg.setEnabled(false);
                                jButtonSendMsg.setEnabled(false);
                                jButtonStopOperation.setEnabled(false);
                                jButtonSendRequestRPC.setEnabled(true);
							} catch (AlreadyClosedException e2) {
								JOptionPane.showMessageDialog(null,
										e2.getMessage(), "ERROR",
										JOptionPane.ERROR_MESSAGE);
                            } catch (IllegalStateException e1) {
                                JOptionPane.showMessageDialog(null,
                                        e1.getMessage(), "ERROR",
                                        JOptionPane.ERROR_MESSAGE);
                            } catch (ENSSubscriptionException e1) {
                                JOptionPane.showMessageDialog(null,
                                        e1.getMessage(), "ERROR",
                                        JOptionPane.ERROR_MESSAGE);
                            } catch (InterruptedException e1) {
                                JOptionPane.showMessageDialog(null,
                                    e1.getMessage(), "ERROR",
                                    JOptionPane.ERROR_MESSAGE);
                            }

							// dispose();
						}
					});
		}
		return jButtonStopOperation;
	}

	/**
	 * This method initializes jButtonInviaMessaggio
	 * 
	 * @return javax.swing.JButton
	 */
	private JButton getJButtonSendMsg() {
		if (jButtonSendMsg == null) {
			jButtonSendMsg = new JButton();
			jButtonSendMsg.setBounds(new Rectangle(5, 373, 125, 18));
			jButtonSendMsg.setText("Start publishing");
			jButtonSendMsg.setFont(new Font("Dialog", Font.BOLD, 11));
			jButtonSendMsg.setForeground(Color.RED);
            jButtonSendMsg.setEnabled(false);
			jButtonSendMsg.addMouseListener(new java.awt.event.MouseAdapter() {
				public void mouseClicked(java.awt.event.MouseEvent e) {
			        if (ENSClientGUI.this.app != null) {
			            if (ENSClientGUI.this.app instanceof ENSPublisher) {
			                ENSPublisher pubApp = (ENSPublisher) ENSClientGUI.this.app;
			                publishingRunnable = new PublishingRunnable(pubApp, ENSClientGUI.this, requestedOperation);
                            publishingThread = new Thread(publishingRunnable);
                            publishingThread.start();
                            jButtonReadMsg.setEnabled(false);
                            jButtonSendMsg.setEnabled(false); 
                            jButtonStopOperation.setEnabled(true);
			            }
			        }       
				}	
			});
		}
		return jButtonSendMsg;
	}

	/**
	 * This method initializes jTextFieldIPHost	
	 * 	
	 * @return javax.swing.JTextField	
	 */
	private JTextField getJTextFieldIPHost() {
		if (jTextFieldIPHost == null) {
			jTextFieldIPHost = new JTextField();
			jTextFieldIPHost.setBounds(new Rectangle(85, 82, 95, 18));
			jTextFieldIPHost.addFocusListener(new java.awt.event.FocusAdapter() {
	            public void focusGained(java.awt.event.FocusEvent e) {
	                unmarkFieldAsMissing(jTextFieldIPHost);
	            }
			});
		}
		return jTextFieldIPHost;
	}

	/**
	 * This method initializes jTextFieldPort	
	 * 	
	 * @return javax.swing.JTextField	
	 */
	private JTextField getJTextFieldPort() {
		if (jTextFieldPort == null) {
			jTextFieldPort = new JTextField();
			jTextFieldPort.setBounds(new Rectangle(85, 101, 95, 18));
			jTextFieldPort.addFocusListener(new java.awt.event.FocusAdapter() {
                public void focusGained(java.awt.event.FocusEvent e) {
                    unmarkFieldAsMissing(jTextFieldPort);
                }
            });
			
		}
		return jTextFieldPort;
	}
    
//    private JProgressBar getJProgressBar() {
//    	if (jProgressBar == null) {
//    		jProgressBar = new JProgressBar();
//    		jProgressBar.setBounds(new Rectangle(5, 122, 365, 14));
//    		jProgressBar.setIndeterminate(false);
//    		jProgressBar.setStringPainted(false);
//    		jProgressBar.setIndeterminate(false);
//    	}
//    	return jProgressBar;
//    }
    
//	public void advancedProgressBar(boolean b) {
//		jProgressBar.setIndeterminate(b);
//	}
	
	private void markFieldAsMissing (JTextField textField) {
	    textField.setBackground(Color.red);
	    textField.setForeground(Color.white);
	    textField.setText("required field");
	}
	
   private void markComboBoxAsMissing (JComboBox comboBox) {
        if (comboBox.getSelectedItem().equals("")) {
            comboBox.setBackground(Color.red);
        }
    }
	
	private void unmarkFieldAsMissing (JTextField textField) {
	    if (textField.getBackground() == Color.red) {
	        textField.setBackground(Color.white);
	        textField.setForeground(Color.black);
	        textField.setText("");
        }
	}
	
	private void clearField (JTextField textField) {
        textField.setBackground(Color.white);
        textField.setForeground(Color.black);
        textField.setText("");
    }
	
	private void unmarkComboBoxAsMissing (JComboBox comboBox) {
	    if (comboBox.getBackground() == Color.red)
	        comboBox.setBackground(backgroundColor);
	}
	private void clearComboBox (JComboBox comboBox) {
        comboBox.setBackground(backgroundColor);
        comboBox.setSelectedIndex(0);
    }
	
	private class SubscriberListener implements ENSEventListener {
	    private static final String TIME_FORMAT = "HH:mm:ss.SSS Z";
        private DateFormat dateFormatter = new SimpleDateFormat(TIME_FORMAT);
        private int i = 0;
        public void onEvent(ENSEvent event) {
            i++;
            StringBuilder msg = new StringBuilder();
            msg.append("-----------------------------------------------------\n");
            msg.append("Message #" + i + "\n");
            msg.append("PublisherID:: " + event.getApplicationID() + "\n");
            msg.append("Timestamp:: " + dateFormatter.format(event.getTimestamp()) + "\n");
            msg.append("Namespace pattern:: " + event.getPattern() + "\n");
            msg.append("Persistent? " + event.isPersistent() + "\n");
            msg.append("Payload media type:: " + event.getContentType() + "\n");
            msg.append("Payload encoding:: " + event.getContentEncoding() + "\n");
            byte[] payload = event.getPayload();
            if (payload == null)
                msg.append("No payload");
            else if (payload.length == 0) 
                msg.append("Empty payload");
            else if (event.getContentType().startsWith("text")) {
                try {
                    String body = new String(payload, event.getContentEncoding());
                    msg.append("Payload:: " + body + "\n");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                
            } else
                msg.append("Payload size:: " + payload.length + " bytes");
            Map<String,Object> headers = event.getHeaders();
            if (headers == null) {
                msg.append("No headers");
            } else {
                msg.append("Headers:");
                for (String key: headers.keySet()) {
                    msg.append("\t\n");
                    msg.append(key);
                    msg.append(": ");
                    msg.append(headers.get(key));
                    msg.append("[class=");
                    msg.append(headers.get(key).getClass().toString());
                    msg.append("]");
                }
            }
            msg.append("\n-----------------------------------------------------\n");
            if (jTextAreaReply == null)
                System.out.println(msg.toString());
            else
                jTextAreaReply.append(msg.toString());
        }
	    
	}
	
	private static class PublishingRunnable implements Runnable{
	    private static final String[] FILLING_LEVELS = new String[] {"min","max","ok"};
        private static final long DELAY = Long.parseLong(
            ApplicationPropertiesRepository.APPLICATION_PROPERTIES
                .getProperty(RequestFactory.ExtraSettings4Publisher.DELAY));
        
	    private ENSPublisher pubApp;
	    private volatile boolean stop;
        private int minRandom;
        private Random randomGenerator;
        private ENSClientGUI notificationRecipient;
        private String requestedOperation;

        private int maxRandom;
	    public PublishingRunnable (ENSPublisher pubApp, ENSClientGUI notificationRecipient, 
	            String requestedOperation) {
	        this.pubApp = pubApp;
	        this.stop = true;
	        this.notificationRecipient = notificationRecipient;
            randomGenerator = new Random();
            maxRandom = Integer.parseInt(ApplicationPropertiesRepository.APPLICATION_PROPERTIES.getProperty(
                    RequestFactory.ExtraSettings4Publisher.MAX_RANDOM,
                    RequestFactory.ExtraSettings4Publisher.DEFAULT_MAX_RANDOM + ""));
            minRandom = Integer.parseInt(ApplicationPropertiesRepository.APPLICATION_PROPERTIES.getProperty(
                    RequestFactory.ExtraSettings4Publisher.MIN_RANDOM,
                    RequestFactory.ExtraSettings4Publisher.DEFAULT_MIN_RANDOM + ""));
            this.requestedOperation = requestedOperation;
	    }
        /* (non-Javadoc)
         * @see java.lang.Runnable#run()
         */
        @Override
        public void run() {
            ENSEvent ensE;
            try {
                stop = false;
                while (!stop && pubApp.isConnected()) {
//                  String mgsTest = "This is just a test. Random integer value = " + 
//                      (randomGenerator.nextInt(maxRandom - minRandom - 1) + minRandom);
                    ensE = createEvent();
                    pubApp.publish(ensE);
                    Thread.sleep(DELAY);
                    System.out.println("Event published: " + ensE.toString());
                }
            } catch (IllegalArgumentException e1) {
                JOptionPane.showMessageDialog(notificationRecipient, e1.getMessage(), 
                        "Publishing error", JOptionPane.ERROR_MESSAGE);
                    e1.printStackTrace();
                System.out.println(e1.getMessage());
                notificationRecipient.jButtonStopOperation.setEnabled(false);
                notificationRecipient.jButtonSendMsg.setEnabled(false);
                notificationRecipient.jButtonSendRequestRPC.setEnabled(true);
            } catch (IllegalStateException e1) {
                JOptionPane.showMessageDialog(notificationRecipient, e1.getMessage(), 
                        "Publishing error", JOptionPane.ERROR_MESSAGE);
                    e1.printStackTrace();
                System.out.println(e1.getMessage());
                notificationRecipient.jButtonStopOperation.setEnabled(false);
                notificationRecipient.jButtonSendMsg.setEnabled(false);
                notificationRecipient.jButtonSendRequestRPC.setEnabled(true);
            } catch (ENSPublishingException e1) {
                JOptionPane.showMessageDialog(notificationRecipient, e1.getMessage(), 
                        "Publishing error", JOptionPane.ERROR_MESSAGE);
                e1.printStackTrace();
                System.out.println(e1.getMessage());
                notificationRecipient.jButtonStopOperation.setEnabled(false);
                notificationRecipient.jButtonSendMsg.setEnabled(false);
                notificationRecipient.jButtonSendRequestRPC.setEnabled(true);
            } catch (InterruptedException e1) {
                JOptionPane.showMessageDialog(notificationRecipient, e1.getMessage(), 
                        "Publishing error", JOptionPane.ERROR_MESSAGE);
                e1.printStackTrace();
                System.out.println(e1.getMessage());
                notificationRecipient.jButtonStopOperation.setEnabled(false);
                notificationRecipient.jButtonSendMsg.setEnabled(false);
                notificationRecipient.jButtonSendRequestRPC.setEnabled(true);
            }
            if (!pubApp.isConnected()) {
                notificationRecipient.jButtonStopOperation.setEnabled(false);
                notificationRecipient.jButtonSendMsg.setEnabled(false);
                notificationRecipient.jButtonSendRequestRPC.setEnabled(true);
            }
            System.out.println("The event publishing has been stopped");
        }
        
        private ENSEvent createEvent () {
//          String urls = ApplicationPropertiesRepository.APPLICATION_PROPERTIES.getProperty(routingKey);
//            if (urls == null)
//                urls = ApplicationPropertiesRepository.APPLICATION_PROPERTIES.getProperty(
//                        ApplicationPropertiesRepository.DEFAULT_DATA_URI);
            
//            String[] uris = urls.split("\\s");
//            String entityDataURI;
//            String entityURI;
//            if (uris.length == 2) {
//                entityURI = uris[0];
//                entityDataURI = uris[1];
//            } else {
//                urls = ApplicationPropertiesRepository.APPLICATION_PROPERTIES.getProperty(
//                        ApplicationPropertiesRepository.DEFAULT_DATA_URI);
//                uris = urls.split("\\s");
//                entityURI = uris[0];
//                entityDataURI = uris[1];
//            }
            StringBuffer payload = new StringBuffer();
            Map<String,Object> headers = new HashMap<String,Object>();
            if (requestedOperation.equals(PUBLISH_BOTTLES_NUMBER)) {
                int value = getRandomInt();
                headers.put("BottlesCounter", value + "");
                payload.append(value);
            }
            else if (requestedOperation.equals(PUBLISH_BOTTLES_WEIGHT)) {
                int value = getRandomInt();
                headers.put("BottlesWeight", value + "");
                payload.append(value);
            }
            else if (requestedOperation.equals(PUBLISH_FILLING_LEVELS)) {
                String value = getRandomFillingLevel();
                headers.put("FillingLevel", value);
                payload.append(value);
            } else if (requestedOperation.equals(PUBLISH_ALERTS)) {
                float value = getRandomFloat();
                headers.put("Power", value);
                payload.append("The pattern of the event source");
            }
            else { //EMD EVENTS
                float value = getRandomFloat();
                headers.put("Power", value + "");
                payload.append(value);
                
                value = getRandomFloat();
                headers.put("Voltage", value + "");
                payload.append(", ");
                payload.append(value);
                
                value = getRandomFloat();
                headers.put("Current", value + "");
                payload.append(", ");
                payload.append(value);
            }
            try {
                return new BasicENSEventFactory().create(
                        headers,payload.toString().getBytes(ENSEvent.DEFAULT_CONTENT_ENCODING), false);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
        
        private float getRandomFloat () {
            return minRandom + (randomGenerator.nextFloat() * (maxRandom-minRandom) + 1);
        }
        
        private int getRandomInt () {
            return randomGenerator.nextInt(minRandom) + (maxRandom-minRandom) + 1;
        }
        
        private String getRandomFillingLevel () {
            return FILLING_LEVELS[randomGenerator.nextInt(FILLING_LEVELS.length)];
        }
        
        public void stop () {
            this.stop = true;
        }
	    
	}
	
}
